package ymlconfig

import (
	"bytes"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
	"go-admin/app/global/app"
	"gopkg.in/yaml.v3"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

var lastChangeTime time.Time

type ymlConfig struct {
	viper      *viper.Viper
	mu         *sync.RWMutex
	configPath string
}

func init() {
	lastChangeTime = time.Now()
}

// CreateYamlFactory 创建 yaml 配置工厂
func CreateYamlFactory(path string, fileName ...string) app.YmlConfigInterface {

	yamlConfig := viper.New()
	// 配置文件所在目录
	yamlConfig.AddConfigPath(path)
	// 需要读取的文件名,默认为：config
	// 确定配置文件名
	configName := "config"
	if len(fileName) > 0 {
		configName = fileName[0]
	}
	yamlConfig.SetConfigName(configName)
	//设置配置文件类型(后缀)为 yml
	yamlConfig.SetConfigType("yml")

	// 读取配置文件
	if err := yamlConfig.ReadInConfig(); err != nil {
		log.Fatal("ReadInConfig err: " + err.Error())
	}
	// 构建完整的配置文件路径
	configPath := filepath.Join(path, configName+".yml")

	return &ymlConfig{
		viper:      yamlConfig,
		mu:         new(sync.RWMutex),
		configPath: configPath, // 保存配置文件完整路径
	}
}

// ConfigFileChangeListen 监听文件变化
func (y *ymlConfig) ConfigFileChangeListen(fns ...func()) {

	y.viper.OnConfigChange(func(changeEvent fsnotify.Event) {
		if time.Since(lastChangeTime).Seconds() >= 1 {
			if changeEvent.Op.String() == "WRITE" {

				// 重新读取配置文件（使用写锁保护）
				y.mu.Lock()
				if err := y.viper.ReadInConfig(); err != nil {
					log.Printf("重新读取配置文件失败: %v", err)
				} else {
					log.Println("配置文件重新加载成功")
				}
				y.mu.Unlock()
				// 执行自定义回调函数
				for _, f := range fns {
					f()
				}
				lastChangeTime = time.Now()
			}
		}
	})
	y.viper.WatchConfig()
}

func (y *ymlConfig) Get(keyName string) interface{} {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.Get(keyName)
	return value
}

func (y *ymlConfig) GetString(keyName string) string {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetString(keyName)
	return value
}

func (y *ymlConfig) GetBool(keyName string) bool {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetBool(keyName)
	return value
}

func (y *ymlConfig) GetInt(keyName string) int {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetInt(keyName)
	return value

}

func (y *ymlConfig) GetInt32(keyName string) int32 {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetInt32(keyName)
	return value
}

func (y *ymlConfig) GetInt64(keyName string) int64 {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetInt64(keyName)
	return value
}

func (y *ymlConfig) GetFloat64(keyName string) float64 {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetFloat64(keyName)
	return value

}

func (y *ymlConfig) GetDuration(keyName string) time.Duration {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetDuration(keyName)
	return value

}

func (y *ymlConfig) GetStringSlice(keyName string) []string {
	y.mu.RLock()
	defer y.mu.RUnlock()
	value := y.viper.GetStringSlice(keyName)
	return value
}

func (y *ymlConfig) GetUintSlice(keyName string) []uint {
	y.mu.RLock()
	defer y.mu.RUnlock()

	// 首先尝试直接获取uint切片
	if value := y.viper.Get(keyName); value != nil {
		if uintSlice, ok := value.([]uint); ok {
			return uintSlice
		}
	}

	// 如果直接获取失败，尝试从int切片转换
	intSlice := y.viper.GetIntSlice(keyName)
	if len(intSlice) == 0 {
		return []uint{}
	}

	// 将int切片转换为uint切片
	uintSlice := make([]uint, len(intSlice))
	for i, v := range intSlice {
		if v < 0 {
			// 如果值为负数，设置为0
			uintSlice[i] = 0
		} else {
			uintSlice[i] = uint(v)
		}
	}

	return uintSlice
}

// Set 设置配置值
func (y *ymlConfig) Set(keyName string, value interface{}) {
	y.mu.Lock()
	defer y.mu.Unlock()
	y.viper.Set(keyName, value)
}

// SaveConfig 使用 goccy/go-yaml 保持注释和顺序
func (y *ymlConfig) SaveConfig() error {
	y.mu.Lock()
	defer y.mu.Unlock()

	// 读取原始文件获取key的顺序和大小写
	originalData, err := os.ReadFile(y.configPath)
	if err != nil {
		return fmt.Errorf("读取配置文件失败: %v", err)
	}

	// 解析为 yaml.Node 以保留注释和结构
	var rootNode yaml.Node
	if err := yaml.Unmarshal(originalData, &rootNode); err != nil {
		return fmt.Errorf("解析YAML失败: %v", err)
	}

	// 获取当前配置值
	currentSettings := y.viper.AllSettings()

	// 更新节点值，保留注释和结构
	if err := y.updateNodeValues(&rootNode, currentSettings); err != nil {
		return err
	}

	// 序列化回 YAML
	var buf bytes.Buffer
	encoder := yaml.NewEncoder(&buf)
	encoder.SetIndent(2) // 设置缩进
	if err := encoder.Encode(&rootNode); err != nil {
		return fmt.Errorf("序列化YAML失败: %v", err)
	}

	// 写回文件
	if err := os.WriteFile(y.configPath, buf.Bytes(), 0644); err != nil {
		return fmt.Errorf("写入配置文件失败: %v", err)
	}

	// 重新读取配置
	if err := y.viper.ReadInConfig(); err != nil {
		return fmt.Errorf("重新读取配置失败: %v", err)
	}

	return nil
}

func (y *ymlConfig) updateNodeValues(node *yaml.Node, current map[string]interface{}) error {
	if node.Kind != yaml.DocumentNode && node.Kind != yaml.MappingNode {
		return nil
	}

	// 处理文档节点
	if node.Kind == yaml.DocumentNode && len(node.Content) > 0 {
		return y.updateNodeValues(node.Content[0], current)
	}

	// 处理映射节点
	if node.Kind == yaml.MappingNode {
		for i := 0; i < len(node.Content); i += 2 {
			keyNode := node.Content[i]
			valueNode := node.Content[i+1]

			if keyNode.Kind == yaml.ScalarNode {
				key := keyNode.Value

				// 在current中查找对应的key（不区分大小写）
				var currentVal interface{}
				found := false

				for k, v := range current {
					if strings.EqualFold(k, key) {
						_ = k
						currentVal = v
						found = true
						break
					}
				}
				if found {
					// 根据值的类型递归处理
					switch typedVal := currentVal.(type) {
					case map[string]interface{}:
						// 嵌套映射
						if valueNode.Kind == yaml.MappingNode {
							y.updateNodeValues(valueNode, typedVal)
						}
					default:
						// 标量值，直接更新
						if valueNode.Kind == yaml.ScalarNode {
							valueNode.Value = fmt.Sprintf("%v", currentVal)
						}
					}
				}
			}
		}
	}
	return nil
}
